package com.hl.card.modular.system.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.hl.card.common.constant.Const;
import com.hl.card.common.persistence.model.Goods;
import com.hl.card.common.remote.user.RemoteUser;
import com.hl.card.common.remote.user.RemoteUserService;
import com.hl.card.common.util.*;
import com.hl.card.core.log.LogObjectHolder;
import com.hl.card.core.shiro.ShiroKit;
import com.hl.card.modular.system.service.IAccessRight;
import com.hl.card.modular.system.service.ISysDicService;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.ui.Model;
import org.springframework.ui.ModelMap;
import org.springframework.web.bind.annotation.RequestMapping;

import javax.servlet.http.HttpServletRequest;
import java.net.InetAddress;
import java.net.UnknownHostException;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
/*
通过微信公扫一扫为操作授权的设计：
一、后台设置一个或者多个微信可信任用户的OpenId(关注了我们的公众号)；

二、操作用户发起对敏感操作的授权请求，请求的内容包括了操作者信息（用户信息、操作终端IP）、申请操作的内容标识等；

三、后台接收到授权请求后根据请求的授权内容生成一段RSA2加密的信息，如果用户的信息和IP信息为为key的redis值存在，并传送过来的信息相等则说明已经授权过，直接返回授权成功，允许进入操作页面。把该信息通过redis以管理员的openid为key存储，然后生成一个访问链接的二维码页面发送给操作申请者的页面显示出来；

四、申请者找到管理员过来后，管理员通过打开我们的公众号进入操作授权页面用扫一扫功能扫描二维码；

五、授权管理服务通过对二维码识别后访问授权服务页面，后台授权服务根据授权者微信信息找到存储在后台的待授权信息，交由授权者授权；

六、管理员核实了操作授权请求信息后点击授权,授权成功，把申请授权的用户的信息和IP信息为为key把授权信息存储；
*/

/**
 * java类简单作用描述
 *
 * @ProjectName: distdev
 * @Package: com.hl.card.modular.pack.service.impl
 * @ClassName: ${TYPE_NAME}
 * @Description: java类作用描述
 * @Author: 作者姓名
 * @CreateDate: 2018/7/9 17:41
 * @UpdateUser: Neil.Zhou
 * @UpdateDate: 2018/7/9 17:41
 * @UpdateRemark: The modified content
 * @Version: 1.0
 * <p>Copyright: Copyright (c) 2018</p>
 */
@Service
public class AccessRightImpl implements IAccessRight {



    private static final Logger logger = LoggerFactory.getLogger(AccessRightImpl.class);
    @Autowired
    private PayUtils payUtils;

    @Autowired
    private StringRedisTemplate stringRedisTemplate;

    @Autowired
    private RemoteUserService remoteUserService;

    @Autowired
    ISysDicService sysDicService;

    @Value("${dismemberapply.ka_ip}")
    private String cpc_ip;

    @Value("${uc.getSMSCodeUrl}")
    private String ucGetSMSCodeUrl;

    @Value("${access.checkUrl}")
    private String accessCheckUrl;
    @Override
    public String checkUser(String userId) {
        return null;
    }

    public String baseCheckAccess(HttpServletRequest request, String toPage) {
        String clientIP = HttpUtils.getIpAddr(request);

        String badPage = "/packback/sysOptAccess/sys_opt_access.html";
        stringRedisTemplate.opsForValue().set(clientIP + "redirectUrl", toPage);

        Boolean result = checkSysOptAccessRight(clientIP);
        if(result) {
            return toPage;
        }else {
            System.out.println("授权失败:" + clientIP);
            return  badPage;
        }
    }

    public String baseCheckWxAccess(HttpServletRequest request, String optId, String toPage, ModelMap model) {
        String clientIP = HttpUtils.getIpAddr(request);

        String badPage = "/packback/sysOptAccess/wxAccessQrCode.html";
        //获取当前操作账户
        String account = ShiroKit.getUser().getAccount();
//        if(ShiroKit.hasRole(Const.ADMIN_NAME)){
//            account = null;
//        }
        stringRedisTemplate.opsForValue().set(account + "-" + clientIP + "redirectUrl", toPage);

        Boolean result = checkWxSysOptAccessRight(optId, clientIP);
        if(StringUtils.isBlank(optId)) {
            return null;
        }
        if(result) {
            return toPage;
        }else {
            System.out.println("授权失败:" + clientIP);
            //生成授权码
            //获取当前操作账户
            account = ShiroKit.getUser().getAccount();
            String name = ShiroKit.getUser().getName();
//        if(ShiroKit.hasRole(Const.ADMIN_NAME)){
//            account = null;
//        }
            String appId = "fklgjior7059kslfngh";
            String wxAdminInfo = stringRedisTemplate.opsForValue().get("SUPER:ACCESS:WX");
            JSONObject wxAdminInfoObj = JSONObject.parseObject(wxAdminInfo);
            String wxOpenId = wxAdminInfoObj.getString("id");
            String wxName = wxAdminInfoObj.getString("name");
            JSONObject accessInfo = new JSONObject();
            accessInfo.put("account", account);
            accessInfo.put("appId", appId);
            accessInfo.put("optId", optId);
            accessInfo.put("appInfo", "卡包");
            accessInfo.put("url", accessCheckUrl + "/access/getWxAccess");
            accessInfo.put("clientIP", clientIP);
            accessInfo.put("wxOpenId", wxOpenId);
            accessInfo.put("name", name);
            accessInfo.put("notify", model.get("notify"));
            accessInfo.put("wxName", wxName);
            accessInfo.put("timeStamp", System.currentTimeMillis());
            String accessCode = MD5Tools.MD5(accessInfo.toJSONString());

            //存储到redis，半小时有效
            stringRedisTemplate.opsForValue().set("SUPER:" + accessCode, accessInfo.toJSONString(), 30, TimeUnit.MINUTES);
            System.out.println("生成的存储信息:" + accessCode + accessInfo.toJSONString());
            //存储accessCode到redis，用于微信扫码后根据微信用户ID获取本次授权码
            stringRedisTemplate.opsForValue().set("SUPER:" + wxOpenId + "accessCode", accessCode, 30, TimeUnit.MINUTES);

            Map<String, Object> item = sysDicService.selectListByCodeNo("CZWXSQ", "url");
            String wxUrl;
            if(item != null) {
                wxUrl = (String) item.get("dicValue");
            }else {
                wxUrl = "https://wx.bibi321.com/wxAuthorizeAccessEntry.html";
            }
            model.put("accessInfo", accessInfo);
            model.put("accessCode", accessCode);
            model.put("toPage", toPage);
            model.put("url", "" + wxUrl);
            return  badPage;
        }
    }

    public boolean getAccessRight(String phone, String rightCode, String clientIP) {
        String temp = stringRedisTemplate.opsForValue().get(phone + clientIP);
        System.out.println("授权IP:" + clientIP);
        System.out.println("接收授权code:" + rightCode);
        System.out.println("正确授权code:" + temp);
        if(StringUtils.isNotBlank(rightCode)) {
            if(rightCode.equals(temp)) {//验证码通过
                if(StringUtils.isNotBlank(clientIP)) {
                    //写入授权,如果使用"SUPER:MANUAL_ACCESS_IP" + clientIP为key，则表示可以同时授权给多台计算机
                    stringRedisTemplate.opsForValue().set("SUPER:MANUAL_ACCESS_IP" + clientIP, clientIP,24, TimeUnit.HOURS);//向redis里存入数据和设置缓存时间
                    //授权5分钟,5分钟内无操作，授权自动失效
                    //stringRedisTemplate.opsForValue().set("SUPER:MANUAL_ACCESS_IP", clientIP, 24, TimeUnit.HOURS);
                    return true;
                }
            }
        }
        return false;
    }

    public boolean getAccessRight(HttpServletRequest request, int expireMinutes) {
        String phone = request.getParameter("phone");
        String rightCode = request.getParameter("rightCode");
        String clientIP = HttpUtils.getIpAddr(request);
        String temp = stringRedisTemplate.opsForValue().get(phone + ":" + clientIP);
        System.out.println("授权IP:" + clientIP);
        System.out.println("接收授权code:" + rightCode);
        System.out.println("正确授权code:" + temp);
        if(StringUtils.isNotBlank(rightCode)) {
            if(rightCode.equals(temp)) {//验证码通过
                if(StringUtils.isNotBlank(clientIP)) {
                    //写入授权,如果使用"phone" + clientIP为key，这里作为通用方法可以同时授权给多台计算机
                    stringRedisTemplate.opsForValue().set(phone + ":" + clientIP, clientIP,expireMinutes, TimeUnit.MINUTES);//向redis里存入数据和设置缓存时间
                    //授权5分钟,5分钟内无操作，授权自动失效
                    //stringRedisTemplate.opsForValue().set("ACCESS_IP", clientIP, 5, TimeUnit.MINUTES);
                    return true;
                }
            }
        }
        return false;
    }

    //获取微信授权,微信授权者通过点击确认授权后，发送授权确认请求，同时微信授权服务需要将授权信息存储到redis，并传输code。
    //后台管理服务在收到请求后通过code取得Redis中的授权详细信息。如果信息存在，授权通过。
    public boolean getWxAccessRight(String wxOpenId, String rightCode, String clientIP) {
        //获取授权详细信息
        System.out.println("授权CODE:" + rightCode);
        String accessInfo = stringRedisTemplate.opsForValue().get(rightCode);
        System.out.println("授权信息:" + accessInfo);
        JSONObject accessInfoObj = null;
        if(StringUtils.isNotBlank(accessInfo)) {
            accessInfoObj = JSONObject.parseObject(accessInfo);
            //对比微信ID
            String temp = stringRedisTemplate.opsForValue().get("SUPER:ACCESS:WX");
            if(!temp.equals(wxOpenId)) {
                return false;
            }
        }

        String account = accessInfoObj.getString("account");
        clientIP = accessInfoObj.getString("clientIP");
        String temp = stringRedisTemplate.opsForValue().get("SUPER:" + wxOpenId + "accessCode");
        String optId = accessInfoObj.getString("optId");
        System.out.println("授权IP:" + clientIP);
        System.out.println("接收授权code:" + rightCode);
        System.out.println("正确授权code:" + temp);
        if(StringUtils.isNotBlank(rightCode)) {
            if(rightCode.equals(temp)) {//验证码通过
                if(StringUtils.isNotBlank(clientIP)) {
                    //写入授权,如果使用"SUPER:MANUAL_ACCESS_IP" + clientIP为key，则表示可以同时授权给多台计算机
                    stringRedisTemplate.opsForValue().set("SUPER:MANUAL_ACCESS_IP:" + optId + ":" + account, clientIP,24, TimeUnit.HOURS);//向redis里存入数据和设置缓存时间
                    //授权5分钟,5分钟内无操作，授权自动失效
                    //stringRedisTemplate.opsForValue().set("SUPER:MANUAL_ACCESS_IP", clientIP, 24, TimeUnit.HOURS);
                    return true;
                }
            }
        }
        return false;
    }

    public boolean getWxAccessRight(HttpServletRequest request, int expireMinutes) {
        //获取当前操作账户
        String account = ShiroKit.getUser().getAccount();
//        if(ShiroKit.hasRole(Const.ADMIN_NAME)){
//            account = null;
//        }
        String phone = request.getParameter("phone");
        String rightCode = request.getParameter("rightCode");
        String clientIP = HttpUtils.getIpAddr(request);
        String temp = stringRedisTemplate.opsForValue().get(phone + ":" + clientIP);
        System.out.println("授权IP:" + clientIP);
        System.out.println("接收授权code:" + rightCode);
        System.out.println("正确授权code:" + temp);
        if(StringUtils.isNotBlank(rightCode)) {
            if(rightCode.equals(temp)) {//验证码通过
                if(StringUtils.isNotBlank(clientIP)) {
                    //写入授权,如果使用"phone" + clientIP为key，这里作为通用方法可以同时授权给多台计算机
                    stringRedisTemplate.opsForValue().set(phone + ":" + clientIP, clientIP,expireMinutes, TimeUnit.MINUTES);//向redis里存入数据和设置缓存时间
                    //授权5分钟,5分钟内无操作，授权自动失效
                    //stringRedisTemplate.opsForValue().set("ACCESS_IP", clientIP, 5, TimeUnit.MINUTES);
                    return true;
                }
            }
        }
        return false;
    }

    public boolean checkWxSysOptAccessRight(String optId, String clientIP) {
        //获取当前操作账户
        String account = ShiroKit.getUser().getAccount();
//        if(ShiroKit.hasRole(Const.ADMIN_NAME)){
//            account = null;
//        }
//        String accessInfo = stringRedisTemplate.opsForValue().get(rightCode);
//        JSONObject accessInfoObj = JSONObject.parseObject(accessInfo);
//        String optId = accessInfoObj.getString("optId");
        String ip = stringRedisTemplate.opsForValue().get("SUPER:MANUAL_ACCESS_IP:" + optId + ":" + account);
        System.out.println("授权IP:" + ip);
        System.out.println("来访IP:" + clientIP);
        if(StringUtils.isNotBlank(clientIP)) {//IP吻合
            if(clientIP.equals(ip)) {//允许操作
                //授权5分钟,5分钟内无操作，授权自动失效
                System.out.println("授权成功:" + clientIP);
                stringRedisTemplate.opsForValue().set("SUPER:MANUAL_ACCESS_IP:" + optId + ":" + account, clientIP, 24, TimeUnit.HOURS);
                return true;
            }
        }
        //说明用户操作环境发生了变化，原授权信息需要清除
        stringRedisTemplate.opsForValue().set("SUPER:MANUAL_ACCESS_IP:" + optId + ":" + account, "null");
        System.out.println("授权失败:" + clientIP);
        return false;
    }

    public boolean checkWxSysOptAccessRight(String optId, String clientIP, String optName) {
        //获取当前操作账户
        System.out.println("授权操作账号:" + optName);
        String account = optName;
//        if(ShiroKit.hasRole(Const.ADMIN_NAME)){
//            account = null;
//        }
//        String accessInfo = stringRedisTemplate.opsForValue().get(rightCode);
//        JSONObject accessInfoObj = JSONObject.parseObject(accessInfo);
//        String optId = accessInfoObj.getString("optId");
        String ip = stringRedisTemplate.opsForValue().get("SUPER:MANUAL_ACCESS_IP:" + optId + ":" + account);
        System.out.println("授权IP:" + ip);
        System.out.println("来访IP:" + clientIP);
        if(StringUtils.isNotBlank(clientIP)) {//IP吻合
            if(clientIP.equals(ip)) {//允许操作
                //授权5分钟,5分钟内无操作，授权自动失效
                System.out.println("授权成功:" + clientIP);
                stringRedisTemplate.opsForValue().set("SUPER:MANUAL_ACCESS_IP:" + optId + ":" + account, clientIP, 24, TimeUnit.HOURS);
                return true;
            }
        }
        System.out.println("授权失败:" + clientIP);
        return false;
    }

    public boolean checkSysOptAccessRight(String clientIP) {
        String ip = stringRedisTemplate.opsForValue().get("SUPER:MANUAL_ACCESS_IP" + clientIP);
        System.out.println("授权IP:" + ip);
        System.out.println("来访IP:" + clientIP);
        if(StringUtils.isNotBlank(clientIP)) {//IP吻合
            if(clientIP.equals(ip)) {//允许操作
                //授权5分钟,5分钟内无操作，授权自动失效
                System.out.println("授权成功:" + clientIP);
                stringRedisTemplate.opsForValue().set("SUPER:MANUAL_ACCESS_IP" + clientIP, clientIP, 24, TimeUnit.HOURS);
                return true;
            }
        }
        System.out.println("授权失败:" + clientIP);
        return false;
    }

    public boolean checkSysOptAccessRight(HttpServletRequest request) {
        String ip = stringRedisTemplate.opsForValue().get("SUPER:MANUAL_ACCESS_IP");
        String clientIP = HttpUtils.getIpAddr(request);
        System.out.println("授权IP:" + ip);
        System.out.println("来访IP:" + clientIP);
        if(StringUtils.isNotBlank(clientIP)) {//IP吻合
            if(clientIP.equals(ip)) {//允许操作
                //授权5分钟,5分钟内无操作，授权自动失效
                System.out.println("授权成功:" + clientIP);
                stringRedisTemplate.opsForValue().set("SUPER:MANUAL_ACCESS_IP" + clientIP, clientIP, 24, TimeUnit.HOURS);
                return true;
            }
        }
        System.out.println("授权失败:" + clientIP);
        return false;
    }

    public boolean checkManualAwardAccessRight(String clientIP) {
        String ip = stringRedisTemplate.opsForValue().get("SUPER:MANUAL_ACCESS_IP" + clientIP);
        System.out.println("授权IP:" + ip);
        System.out.println("来访IP:" + clientIP);
        if(StringUtils.isNotBlank(clientIP)) {//IP吻合
            if(clientIP.equals(ip)) {//允许操作
                //授权5分钟,5分钟内无操作，授权自动失效
                System.out.println("授权成功:" + clientIP);
                stringRedisTemplate.opsForValue().set("SUPER:MANUAL_ACCESS_IP" + clientIP, clientIP, 24, TimeUnit.HOURS);
                return true;
            }
        }
        System.out.println("授权失败:" + clientIP);
        return false;
    }

    public boolean checkAccessRight(HttpServletRequest request, int expireMinutes) {
        String phone = request.getParameter("phone");
        String clientIP = HttpUtils.getIpAddr(request);
        String ip = stringRedisTemplate.opsForValue().get(phone + ":" + clientIP);
        System.out.println("授权IP:" + ip);
        System.out.println("来访IP:" + clientIP);
        if(StringUtils.isNotBlank(clientIP)) {//IP吻合
            if(clientIP.equals(ip)) {//允许操作
                //授权5分钟,5分钟内无操作，授权自动失效
                System.out.println("授权成功:" + clientIP);
                stringRedisTemplate.opsForValue().set(phone + ":" + clientIP, clientIP, expireMinutes, TimeUnit.MINUTES);//默认两小时有效
                return true;
            }
        }
        System.out.println("授权失败:" + clientIP);
        return false;
    }

    public boolean getAccessRightCode(HttpServletRequest request, int expireMinutes) {
        String phone = request.getParameter("phone");
        String clientIP = HttpUtils.getIpAddr(request);
        return sendSMSCode(phone, clientIP, expireMinutes);
    }

    private boolean sendSMSCode(String phoneNum, String clientIP, int expireMinutes) {
        //String accessPhone = stringRedisTemplate.opsForValue().get("SUPER:ACCESS:ADMIN_PHONE:MANUAL_AWARD");
//        if(StringUtils.isBlank(accessPhone)) {
//            //预设手机号
//            accessPhone = "18124021006";
//        }
        if(StringUtils.isBlank(phoneNum) || StringUtils.isBlank(clientIP)) {
            System.out.println("手机号或者ip为空");
            return false;
        }
        String SMSCode = RandomStrUtils.getInstance().createRandomNumString(6);

        JSONObject result = remoteUserService.sendPCode(phoneNum, SMSCode);

        System.out.println(result.toJSONString());

        String resCode = result.getString("code");
        if("0".equals(resCode)) {
            stringRedisTemplate.opsForValue().set(phoneNum + ":" + clientIP, SMSCode,expireMinutes, TimeUnit.MINUTES);//向redis里存入数据和设置缓存时间, 默认30分钟有效
            return true;
        }
        return false;
    }

    public boolean sendSMSCode(String phoneNum, String clientIP) {
        String accessPhone = stringRedisTemplate.opsForValue().get("SUPER:ACCESS:ADMIN_PHONE:MANUAL_AWARD");
        if(StringUtils.isBlank(accessPhone)) {
            accessPhone = "18124021006";
        }
        if(StringUtils.isBlank(phoneNum) || StringUtils.isBlank(clientIP)) {
            System.out.println("手机号或者ip为空");
            return false;
        }
        String SMSCode = RandomStrUtils.getInstance().createRandomNumString(6);

        JSONObject result = remoteUserService.sendPCode(accessPhone, SMSCode);

        System.out.println(result.toJSONString());

        String resCode = result.getString("code");
        if("0".equals(resCode)) {
            stringRedisTemplate.opsForValue().set(phoneNum + clientIP, SMSCode,24, TimeUnit.HOURS);//向redis里存入数据和设置缓存时间
            return true;
        }
        return false;
    }

    /*
    获取用户特征码，特征码用于记录用户在平台的操作相关信息，如果信息不完整，将拒绝用户的任何访问.
    需要预先对重要接口进行特征分组，每组更具业务不同可以有多个特征码，特征码通过二进制编码，每组特征码占用16bit，也就是说每组最多支持16个子特征
    比如
    通用特征组：COMMON
    登录：
    答题特征组：TRAIN
    包含其他的特征：COMMON
    获取用户当前答题状态：0x0000000000000001
    获取当前答题配置信息：0x0000000000000010

    签到特征组：SIGN
    包含其他的特征：COMMON
    获取用户当前签到状态：0x0000000000000001
    获取当前签到配置信息：0x0000000000000010

    短信特征组：SMSSEND
    包含其他的特征：COMMON
    获取用户当前答题状态：0x0000000000000001
    获取当前答题配置信息：0x0000000000000010

     */
    public String getCharacterCode(String clientIp) {
        String code = stringRedisTemplate.opsForValue().get(clientIp + ":" + "fjruu548a&84r9");
        return code;
    }

    public String getUserCharacterCode(String userId) {
        String code = stringRedisTemplate.opsForValue().get(userId + ":" + "fjruu548a&84r9");
        return code;
    }

        /*
    记录用户特征码，特征码用于记录用户在平台的操作相关信息，如果信息不完整，将拒绝用户的任何访问.
    需要使用特征码验证的API将不做特征统计，
     */
    public String setCharacterCode(String clientIp, String api) {
        String code = stringRedisTemplate.opsForValue().get(clientIp + ":" + "fjruu548a&84r9");
        return code;
    }

    public String setUserCharacterCode(String userId, String clientIp, String api) {
        String code = stringRedisTemplate.opsForValue().get(userId + clientIp + ":" + "fjruu548a&84r9");
        return code;
    }
}
